// finally方法实现
/**
 * const p2 = new Promise((resolve,reject)=>{
			reject("succ");
		})
		p2.finally(()=>{
			// 不论成功或失败，都会调用这里的逻辑
			// 然后可以再调用then
		}).then((v)=>{
			console.log("---->",v)
		})


		const p2 = new MyPromise((resolve,reject)=>{
			resolve("s");
		})
		p2.finally(()=>{
			// 不论成功或失败，都会调用这里的逻辑
			// 然后可以再调用then
			return p; //如果finally中返回了promise对象，则会等待promise对象的构造器执行完，再执行then方法,then的回调针对p2
		}).then((v)=>{
			console.log("---->",v)
		},(r)=>{
			console.log("000",r)
		})
 */

// 维护三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
	// executor 执行器函数，参数为resolve函数，reject函数
	constructor(executor) { //executor立即执行
		try{
			executor(this.resolve, this.reject);
		}catch(e){
			this.reject(`执行器运行时错误：${e.message}`);
		}
		
	}

	status = PENDING;// 默认状态
	value = undefined;//成功之后的值 - 使用方传入
	reason = undefined;//失败的原因 - 使用方传入

	successCallback = [];//成功回调
	failCallback = [];// 失败回调


	// 直接调用一个函数(不使用点调用)，那么该函数中的this指向window或undefiend
	// 注意：函数作为类的属性，通常使用箭头函数,这样，直接调用函数时(不使用点调用)，该函数中的this就始终指向该对象的实例
	resolve = value => {
		this.value = value;
		// 保证状态只能被修改一次
		if (this.status !== PENDING) {
			return;
		}
		this.status = FULFILLED;
		// 把所有调用了then方法的回调函数统统执行一遍
		while (this.successCallback.length) this.successCallback.shift()();
	};
	reject = reason => {
		this.reason = reason;
		// 保证状态只能被修改一次
		if (this.status !== PENDING) {
			return;
		}
		this.status = REJECTED;
		// 把所有调用了then方法的回调函数统统执行一遍
		while (this.failCallback.length) this.failCallback.shift()();
	};

	// then是被定义在原型对象中的，在对象的原型对象中定义函数then的写法: then(){} ; 非箭头函数
	// 判断状态，并决定执行resolve还是reject


	// 链式调用解决方法：

	then(successCallback, failCallback) {
		successCallback = successCallback?successCallback:value=>value;
		failCallback = failCallback?failCallback:reason=>{throw reason};
		let promise2 = new MyPromise((resolve, reject) => { //实例化后，立即执行该函数
			if (this.status === FULFILLED) {
				// 为了获取到完整的promise2对象，这里用异步的形式进行获取peomise2并传参
				setTimeout(() => {
					try{
						let x = successCallback(this.value); //保存返回值，作为下一次链式调用中then的参数
						// x如果是普通值，则直接调用resove
						// x如果是Promise对象，查看promise对象返回的结果
						// 再根据promise返回的结果，决定调用resolve还是reject
						resolvePromise(promise2, x, resolve, reject);// 以上三行使用resolvePromise函数实现
					}catch(e){
						reject(e)
					}
				}, 0);
			} else if (this.status === REJECTED) {
				setTimeout(() => {
					try{
						let x = failCallback(this.reason); //保存返回值，作为下一次链式调用中then的参数
						resolvePromise(promise2, x, resolve, reject); // 通过调用promise的reject方法，来传递上一次then的返回值作为下一个then的参数值
					}catch(e){
						reject(e)
					}
				}, 0)
			} else {
				// 此处如果执行，说明一定存在异步代码
				// PENDING状态
				this.successCallback.push(()=>{
					setTimeout(() => {
						try{
							let x = successCallback(this.value); //保存返回值，作为下一次链式调用中then的参数
							resolvePromise(promise2, x, resolve, reject);// 以上三行使用resolvePromise函数实现
						}catch(e){
							reject(e)
						}
					}, 0);
				});
				this.failCallback.push(()=>{
					setTimeout(() => {
						try{
							let x = failCallback(this.reason); //保存返回值，作为下一次链式调用中then的参数
							resolvePromise(promise2, x, resolve, reject); // 通过调用promise的reject方法，来传递上一次then的返回值作为下一个then的参数值
						}catch(e){
							reject(e)
						}
					}, 0)
				});
			}
		});

		return promise2;
	}

	finally(callback){
		return this.then(value=>{
			// 需考虑异步代码，如若此处返回的是Promise异步对象
			return MyPromise.resolve(callback()).then(()=>value);

		},reason=>{
			return MyPromise.resolve(callback()).then(()=>{throw reason})
		})
	}

	/**
	 * all 静态方法
	 * @param array 元素可以是普通值 or Promise对象
	 */
	static all(array){
		let result = [];
		let index = 0;// 解决异步代码问题
		
		return new MyPromise((resolve,reject)=>{
			function addData(key, value){
				result[key] = value;
				index++;
				if(index === array.length){
					resolve(result);
				}
			}
			for(let i=0;i<array.length;i+=1){
				let current = array[i];
				if(current instanceof MyPromise){
					current.then((value)=>addData(i,value),(reason)=>{reject(reason)})
				}else{
					addData(i,current);
				}
			}
			
		})
	}

	static resolve(value){
		if(value instanceof MyPromise) return value;
		return new MyPromise((resolve)=>{resolve(value)});
	}

}
function resolvePromise(promise2, x, resolve, reject) {
	if (promise2 === x) {
		return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
		// return用来阻止代码继续执行
	}
	if (x instanceof MyPromise) {
		// promise对象
		// x.then(value => resolve(value), reason => reject(reason));
		// 简化为以下：
		x.then(resolve, reject);
	} else {
		// 普通值
		resolve(x);
	}
}
module.exports = MyPromise;